package utils

import (
	"os"
	"time"
	"fmt"
	"sync"
	"github.com/op/go-logging"
	"github.com/gin-gonic/gin"
)

var (
	handlerLog *logging.Logger
	systemLog  *logging.Logger
	mutex      sync.Mutex
)

const (
	FATAL    = "fatal"
	DEBUG    = "debug"
	ERROR    = "error"
)

func init() {
	srvCfg := GetConfig().Server
	handlerLog = logging.MustGetLogger("handler")
	handlerFmt := logging.NewBackendFormatter(
		logging.NewLogBackend(os.Stderr, "[WEB] ", 0),
		logging.MustStringFormatter(srvCfg.WebLogFmt))
	handlerLog.SetBackend(logging.AddModuleLevel(handlerFmt))

	systemLog = logging.MustGetLogger("system")
	systemFmt := logging.NewBackendFormatter(
		logging.NewLogBackend(os.Stderr, "[SYS] ", 0),
		logging.MustStringFormatter(srvCfg.SysLogFmt))
	systemLog.SetBackend(logging.AddModuleLevel(systemFmt))

	System("logger registered")
}

func System(v ...interface{}) {
	go func() {
		mutex.Lock()
		defer mutex.Unlock()
		systemLog.Critical(v)
	}()
}

func Fatal(v ...interface{}) {
	systemLog.Fatal(v)
}

func Handler(notLogged ...string) gin.HandlerFunc {
	var skip map[string]struct{}
	if length := len(notLogged); length > 0 {
		skip = make(map[string]struct{}, length)
		for _, path := range notLogged {
			skip[path] = struct{}{}
		}
	}

	return func(c *gin.Context) {
		// Start timer
		start := time.Now()
		path := c.Request.URL.Path

		// Process yclient
		c.Next()

		// Log only when path is not being skipped
		if _, ok := skip[path]; !ok {
			end := time.Now()
			latency := end.Sub(start)
			//clientIP := c.ClientIP()
			method := c.Request.Method
			code := c.Writer.Status()
			comment := c.Errors.ByType(gin.ErrorTypePrivate).String()
			msg := fmt.Sprintf("%3d | %10v | %-4s  %s  %s",
				code, latency, method, path, comment)
			switch {
			case code < 200:
				handlerLog.Warning(msg)
			case code < 300:
				handlerLog.Notice(msg)
			case code < 400:
				handlerLog.Info(msg)
			case code < 500:
				handlerLog.Error(msg)
			default:
				handlerLog.Critical(msg)
			}
		}
	}
}
